package cn.net.shuxing.yifu.common.front.controller;


import cn.net.shuxing.yifu.common.bean.*;
import cn.net.shuxing.yifu.common.constant.*;
import cn.net.shuxing.yifu.common.dto.BaseDto;
import cn.net.shuxing.yifu.common.service.*;
import cn.net.shuxing.yifu.common.util.*;
import cn.net.shuxing.yifu.config.WXPayConfigImpl;
import cn.net.shuxing.yifu.config.WxpayParam;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.jdom.JDOMException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import cn.net.shuxing.yifu.common.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;


@RestController
public class WxPayController {

    private String ip = "47.98.205.250";

    @Autowired
    private WxBankNumMap wxBankNumMap;

    @Autowired
    private RechargeHistoryService rechargeHistoryService;

    @Autowired
    private UserBankCardService userBankCardService;

    @Autowired
    private UserWithdrawalCashService userWithdrawalCashService;
    @Autowired
    private JedisUtil jedisUtil;

    @Autowired
    private UserService userService;

    @Autowired
    private CashWalletService cashWalletService;

    @Autowired
    private UserDealHistoryService userDealHistoryService;

    @Autowired
    private UserCashHistoryService userCashHistoryService;

    @ApiOperation(value = "调起付款", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "body", value = "描述", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "totalFee", value = "总价,单位是分", required = true, dataType = "String", paramType = "query"),
    })
    @RequestMapping("/front/pay/wxpay")
    public BaseDto wxPayFunction(String totalFee, Integer userId) throws Exception {
        // 保存支付信息
        RechargeHistory rechargeHistory = new RechargeHistory();
        UserCashHistory userCashHistory = new UserCashHistory();
        User user = userService.getByPrimaryKey(userId);
        if (user == null)
            return BaseDto.error("用户不存在");
        rechargeHistory.setUserId(userId);
        userCashHistory.setUserId(userId);
        Date now = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//可以方便地修改日期格式
        String order_no = dateFormat.format(now);  //生成商户订单号，不可重复
        String orderNo = userDealHistoryService.createOrderNo(8);
        userCashHistory.setOrderKey(orderNo);
        BigDecimal ccount = new BigDecimal(new BigDecimal(totalFee).divide(new BigDecimal(100)).toString());
        userCashHistory.setCount(ccount);
        userCashHistory.setType(CashChangeType.CASH_RECHAREGE);
        userCashHistory.setUserType(user.getType());
        userCashHistoryService.insert(userCashHistory);

        rechargeHistory.setOrderNo(orderNo);
        rechargeHistory.setFee(new BigDecimal(totalFee).divide(new BigDecimal(100)).toString());
        rechargeHistory.setSubject("用户充值");
        rechargeHistory.setPaymentStatus(PaymentStatus.UNPAID.name());
        String outTradeNo = order_no + userDealHistoryService.createOrderNo(18);
        rechargeHistory.setOutTradeNo(outTradeNo);
        rechargeHistoryService.insert(rechargeHistory);
        if (rechargeHistory.getId() != null){

        WxpayParam wxpayParam = new WxpayParam("用户充值", totalFee, outTradeNo);
        String notifyUrl = "http://47.98.205.250/front/notify/wxpay";  //我这里的回调地址是随便写的，到时候需要换成处理业务的回调接口

        WXPayConfigImpl ourWxPayConfig = WXPayConfigImpl.getInstance();
        WXPay wxPay = new WXPay(ourWxPayConfig);

        //根据微信支付api来设置
//        Map<String, String> data = new HashMap<>();
        SortedMap<String,String> data = new TreeMap<String,String>();
        data.put("appid", ourWxPayConfig.getAppID());
        data.put("mch_id", ourWxPayConfig.getMchID());         //商户号
        data.put("trade_type", "APP");                         //支付场景 APP 微信app支付 JSAPI 公众号支付  NATIVE 扫码支付
        data.put("notify_url", notifyUrl);                     //回调地址
        data.put("spbill_create_ip", ip);             //终端ip
        data.put("total_fee", wxpayParam.getTotalFee());       //订单总金额
        data.put("fee_type", "CNY");                           //默认人民币
        data.put("out_trade_no", wxpayParam.getOutTradeNo());   //交易号
        data.put("body", wxpayParam.getBody());
        data.put("nonce_str", UUID.randomUUID().toString().substring(0, 20));   // 随机字符串小于32位
        String sign = WXPayUtil.generateSignature(data, ourWxPayConfig.getKey());  //签名
        data.put("sign", sign);

//        List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(data.entrySet());
//        //对所有传入参数按照字段名的ASCII码从小到大排序（字典序）
//        Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
//            public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
//                return (o1.getKey()).toString().compareTo(o2.getKey());
//            }
//        });

        /** wxPay.unifiedOrder 这个方法中调用微信统一下单接口 */
        System.out.println(data.toString());
        Map<String, String> respData = wxPay.unifiedOrder(data);
        System.out.println("微信支付返回数据" + respData);
        if (respData.get("return_code").equals("SUCCESS")) {
            //返回给APP端的参数，APP端再调起支付接口
            SortedMap<String,String> repData = new TreeMap<String,String>();
//            repData.put("appid", ourWxPayConfig.getAppID());
//            repData.put("partnerid", ourWxPayConfig.getMchID());
//            repData.put("prepayid", respData.get("prepay_id"));
//            repData.put("package", "WXPay");
//            repData.put("noncestr", respData.get("nonce_str"));
//            repData.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
            repData.put("appid", ourWxPayConfig.getAppID());
            repData.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
            repData.put("noncestr", respData.get("nonce_str"));
            repData.put("package", "WXPay");
            repData.put("partnerid", ourWxPayConfig.getMchID());
            repData.put("prepayid", respData.get("prepay_id"));

            sign = WXPayUtil.generateSignature(repData, ourWxPayConfig.getKey()); //签名
            respData.put("sign", sign);
            respData.put("timestamp", repData.get("timestamp"));
            respData.put("package", "WXPay");
            rechargeHistory.setPrepayId(respData.get("prepay_id"));
            rechargeHistoryService.update(rechargeHistory);
            System.out.println("微信支付统一下单接口调用完毕+"+respData);

            return BaseDto.ok(respData);
        }

        throw new Exception(respData.get("return_msg"));
        }
        System.out.println("微信支付统一下单接口调用完毕");
        return BaseDto.error("数据库未插入预付款的订单id.");
    }

    /**
     * 此函数会被执行多次，如果支付状态已经修改为已支付，则下次再调的时候判断是否已经支付，如果已经支付了，则什么也执行
     *
     * @param request
     * @param response
     * @return
     * @throws IOException
     * @throws JDOMException
     */
    @RequestMapping(value = "/front/notify/wxpay", produces = MediaType.APPLICATION_JSON_VALUE)
    // @RequestDescription("支付回调地址")
    public String notifyWeiXinPay(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {
        System.out.println("微信支付回调");
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        String resultxml = new String(outSteam.toByteArray(), "utf-8");
        Map<String, String> params = null;
        try {
            params = PayCommonUtil.doXMLParse(resultxml);
        } catch (JDOMException e) {
            e.printStackTrace();
        }
        outSteam.close();
        inStream.close();


        Map<String, String> return_data = new HashMap<String, String>();
        if (!PayCommonUtil.isTenpaySign(params)) {
            // 支付失败
            return_data.put("return_code", "FAIL");
            return_data.put("return_msg", "支付错误-01");
            return StringUtil.GetMapToXML(return_data);
        } else {
            System.out.println("===============付款成功==============");
//             ------------------------------
//             处理业务开始
//             ------------------------------
//             此处处理订单状态，结合自己的订单数据完成订单状态的更新
//             ------------------------------
            String total_fee = params.get("total_fee");
            double v = Double.valueOf(total_fee) / 100;
            String out_trade_no = String.valueOf(Long.parseLong(params.get("out_trade_no").split("O")[0]));
            Date accountTime = DateUtil.stringtoDate(params.get("time_end"), "yyyyMMddHHmmss");
            String ordertime = DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss");
            String totalAmount = String.valueOf(v);
            String appId = params.get("appid");
            String tradeNo = params.get("transaction_id");

            RechargeHistory rechargeHistoryUpd = new RechargeHistory();
            rechargeHistoryUpd.clearCreateTimeAndUpdateTime();
            rechargeHistoryUpd.setOutTradeNo(out_trade_no);
            rechargeHistoryUpd = rechargeHistoryService.get(rechargeHistoryUpd);
            // 设置状态
            rechargeHistoryUpd.setPaymentStatus(PaymentStatus.PAID.name());
            // 设置创建时间
            rechargeHistoryUpd.setCallbackTime(LocalDateTime.now());
            // 设置内容
            rechargeHistoryUpd.setCallbackContent(params.get("attach"));
            rechargeHistoryService.update(rechargeHistoryUpd);

            return_data.put("return_code", "SUCCESS");
            return_data.put("return_msg", "OK");
            return StringUtil.GetMapToXML(return_data);
        }
    }

    @ApiOperation(value = "提现到银行卡", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userBankCardId", value = "用户银行卡的id(不是银行卡号,是userBankCard对象的id属性)", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "withdrawCount", value = "提现金额", required = true, dataType = "double", paramType = "query"),
    })
    @RequestMapping("/front/withdraw/wxpay")
    public BaseDto withdraw(Integer userBankCardId, BigDecimal withdrawCount,
                            @RequestParam(value = "desc", defaultValue = "") String desc) throws Exception {

        UserBankCard userBankCard = userBankCardService.getByPrimaryKey(userBankCardId);
        if (userBankCard == null) {
            BaseDto baseDto = new BaseDto();
            baseDto.setCode(CodeConst.ERROR);
            baseDto.setMsg("此银行卡不存在,请检查");
            return baseDto;
        }

        Map<String, String> paramMap = new HashMap<>();
        WXPayConfigImpl ourWxPayConfig = WXPayConfigImpl.getInstance();
        paramMap.put("mch_id", ourWxPayConfig.getMchID());
        String partnerTradeNo = UUID.randomUUID().toString().substring(0, 20);
        paramMap.put("partner_trade_no", partnerTradeNo);
        paramMap.put("nonce_str", UUID.randomUUID().toString().substring(0, 20));
        String sign = WXPayUtil.generateSignature(paramMap, ourWxPayConfig.getKey());  //签名
        paramMap.put("sign", sign);
        /** 这里的enc_bank_no需要RSA加密,但我还没有加密 **/
        paramMap.put("enc_bank_no", userBankCard.getBankCardNum());
        paramMap.put("enc_true_name", userBankCard.getHolderName());
        paramMap.put("bank_code", wxBankNumMap.get(userBankCard.getOpenBank()));
        paramMap.put("amount", withdrawCount.multiply(new BigDecimal(100)).toString());
        paramMap.put("desc", desc);

        /** 将提现申请存入数据库 **/
        UserWithdrawalCash userWithdrawalCash = new UserWithdrawalCash();
        userWithdrawalCash.setUserId(userBankCard.getUserId());
        userWithdrawalCash.setPartnerTradeNo(partnerTradeNo);
        userWithdrawalCash.setApplyBank(userBankCard.getOpenBank());
        userWithdrawalCash.setApplyBankCardNum(userBankCard.getBankCardNum());
        userWithdrawalCash.setState(UserWithdrawalState.TRANSFERING);
        userWithdrawalCash.setUserBankCardId(userBankCardId);
        userWithdrawalCashService.insert(userWithdrawalCash);


        String url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
        /** 发起提现请求 **/
        String responseStr = HttpClientUtil.doPost(url, paramMap);
        JSONObject responseMap = JSON.parseObject(responseStr);
        if (responseMap.get("return_code").equals("FAIL")) {
            /** 这是微信返回的错误信息 **/
            String errorMsg = responseMap.getString("return_msg");
            BaseDto baseDto = new BaseDto();
            baseDto.setData("转账中");
            /** 这里写给后台的提示信息 **/

            /** 暂时空着 **/
            return baseDto;
        } else {
            if (responseMap.get("result_code").equals("FAIL")) {
                /** 这是微信返回的错误信息 **/
                String errorCode = responseMap.getString("err_code");
                String errorCodeDes = responseMap.getString("err_code_des");

                BaseDto baseDto = new BaseDto();
                baseDto.setData("转账中");
                /** 这里写给后台的提示信息 **/
                /** 暂时空着 **/
                return baseDto;
            } else {
                userWithdrawalCash.setState(UserWithdrawalState.COMPLETED);
                userWithdrawalCashService.update(userWithdrawalCash);
                BaseDto baseDto = new BaseDto();
                baseDto.setData("提现完成,三个工作日内到账");
                return baseDto;
            }
        }
    }

    /**
     * 手动提现
     *
     * @param userBankCardId
     * @param withdrawCount
     * @param desc
     * @return
     */
    @RequestMapping("/front/withdraw/manual")
    public BaseDto withdrawManual(Integer userBankCardId, Integer withdrawCount,
                                  @RequestParam(value = "desc", defaultValue = "") String desc) {
        //Jedis //jedis = jedisUtil.getJedis();
        String s = jedisUtil.get(RedisKeyCreator.rechargeBaseCount());
        //jedisUtil.close();
        Integer baseCount = 0;
        if (StringUtils.hasText(s))
            baseCount = Integer.valueOf(s);
        if (baseCount.compareTo(withdrawCount) > 0)
            return BaseDto.error("充值金额至少为" + baseCount.floatValue());
        UserBankCard userBankCard = userBankCardService.getByPrimaryKey(userBankCardId);
        if (userBankCard == null) {
            BaseDto baseDto = new BaseDto();
            baseDto.setCode(CodeConst.ERROR);
            baseDto.setMsg("此银行卡不存在,请检查");
            return baseDto;
        }
        /** 将提现申请存入数据库 **/
        UserWithdrawalCash userWithdrawalCash = new UserWithdrawalCash();
        userWithdrawalCash.setUserId(userBankCard.getUserId());
        userWithdrawalCash.setPartnerTradeNo(null);
        userWithdrawalCash.setApplyBank(userBankCard.getOpenBank());
        userWithdrawalCash.setApplyBankCardNum(userBankCard.getBankCardNum());
        userWithdrawalCash.setState(UserWithdrawalState.TRANSFERING);
        userWithdrawalCash.setUserBankCardId(userBankCardId);
        userWithdrawalCash.setApplyMoney(withdrawCount);
        userWithdrawalCashService.insert(userWithdrawalCash);
        /** 扣除现金钱包里的钱 **/
        CashWallet cashWallet = cashWalletService.getByPrimaryKey(userBankCard.getUserId());
        BigDecimal cashCount = cashWallet.getCashCount();
        BigDecimal withdrawCountDecimal = new BigDecimal(withdrawCount).divide(new BigDecimal(100));
        if (cashCount.compareTo(withdrawCountDecimal) < 0)
            return BaseDto.error("现金钱包余额不足");
        cashWalletService.reduceCash(userBankCard.getUserId(), withdrawCountDecimal, CashChangeType.CASH_WITHDRAW, userWithdrawalCash.getId().toString());


        /** 计算手续费 **/
        //jedis = jedisUtil.getJedis();
        double fee = Double.parseDouble(jedisUtil.get(RedisKeyCreator.userWithdrawFeeRatio()));
        //jedisUtil.close();
        int feeCount = (int) ((double) withdrawCount * fee);
        int factMoney = withdrawCount - feeCount;
        userWithdrawalCash.setFactMoney(factMoney);


        return BaseDto.ok("success");
    }


}